
import pandas as pd
import numpy as np
df = pd.read_csv('earthquakes_2023_global_bruite.csv', delimiter = ';')
df
| time | latitude | longitude | depth | mag | magType | nst | gap | dmin | rms | ... | updated | place | type | horizontalError | depthError | magError | magNst | status | locationSource | magSource | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2023-01-01T00:49:25.294Z | 52.0999 | 178.5218 | 82.770 | 3.10 | ml | 14.0 | 139.0 | 0.8700 | 0.18 | ... | 2023-03-11T22:51:52.040Z | Rat Islands, Aleutian Islands, Alaska | earthquake | 8.46 | 21.213 | 0.097 | 14.0 | reviewed | us | us |
| 1 | 2023-01-01T01:41:43.755Z | 7.1397 | 126.7380 | 79.194 | 4.50 | mb | 32.0 | 104.0 | 1.1520 | 0.47 | ... | 2023-03-11T22:51:45.040Z | 23 km ESE of Manay, Philippines | earthquake | 5.51 | 7.445 | 0.083 | 43.0 | reviewed | us | us |
| 2 | 2023-01-01T03:29:31.070Z | 19.1631 | -66.5251 | 24.000 | 3.93 | md | 23.0 | 246.0 | 0.8479 | 0.22 | ... | 2023-03-11T22:51:29.040Z | Puerto Rico region | earthquake | 0.91 | 15.950 | 0.090 | 16.0 | reviewed | pr | pr |
| 3 | 2023-01-01T04:09:32.814Z | -4.7803 | NaN | 63.787 | 4.30 | mb | 17.0 | 187.0 | 0.4570 | 0.51 | ... | 2023-03-11T22:51:45.040Z | 99 km SSW of Pagar Alam, Indonesia | earthquake | 10.25 | 6.579 | 0.238 | 5.0 | reviewed | us | us |
| 4 | 2023-01-01T04:29:13.793Z | 53.3965 | -166.9417 | 10.000 | 3.00 | ml | 19.0 | 190.0 | 0.4000 | 0.31 | ... | 2023-03-11T22:51:38.040Z | 59 km SSW of Unalaska, Alaska | earthquake | 1.41 | 1.999 | 0.085 | 18.0 | reviewed | us | us |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 26637 | 2023-12-29T03:37:19.334Z | -6.9527 | 154.9829 | 10.000 | 5.20 | mb | 72.0 | 60.0 | 3.9240 | 0.93 | ... | 2023-12-29T04:05:57.040Z | 89 km SW of Panguna, Papua New Guinea | earthquake | 10.07 | 1.765 | 0.048 | 141.0 | reviewed | us | us |
| 26638 | 2023-12-29T04:38:54.109Z | 32.3262 | 141.7386 | 10.000 | 5.10 | mb | 74.0 | 121.0 | 1.8030 | 0.70 | ... | 2023-12-29T10:59:44.533Z | Izu Islands, Japan region | earthquake | 9.17 | 1.870 | 0.042 | 187.0 | reviewed | us | us |
| 26639 | 2023-12-29T08:42:05.747Z | -7.2411 | 68.0663 | 10.000 | 5.10 | mb | 60.0 | 54.0 | 12.7760 | 0.57 | ... | 2023-12-29T08:57:05.040Z | Chagos Archipelago region | earthquake | 8.02 | 1.792 | 0.090 | 40.0 | reviewed | us | us |
| 26640 | 2023-12-29T11:02:48.679Z | -19.1602 | 169.0428 | 153.264 | 4.70 | mb | 40.0 | 61.0 | 3.7460 | 0.82 | ... | 2023-12-29T11:22:46.040Z | 49 km NNW of Isangel, Vanuatu | earthquake | 8.52 | 7.433 | 0.081 | 46.0 | reviewed | us | us |
| 26641 | 2023-12-29T16:31:16.656Z | 25.1050 | 96.5309 | 10.000 | 5.00 | mb | 53.0 | 64.0 | 4.1560 | 0.78 | ... | 2023-12-29T16:45:27.040Z | 92 km WSW of Myitkyina, Myanmar | earthquake | 7.85 | 1.876 | 0.071 | 64.0 | reviewed | us | us |
26642 rows × 22 columns
Nous avons remarqué que le dataset ne se chargeait pas correctement lorsque nous mettions une , en délimiteur (certaines valeurs se retoruvaient dans une seule colonne). En explorant, nous avons remarqué que certaines lignes avaient des "dans les colonnes ce qui nous empêchait de lire les données correctement. Pour régler ça, nous avons ouvert le dataset sur Excel pour le transformer avec , comme délimiteur. Puis nous l'avons de nouveau ouvert avec Python en utilisant ; comme délimiteur.
Le nettoyage de données est une étape importante lorsque l'on souhaite analyser des données. Il sert à préparer et à traiter les données brutes pour les rendre utilisables et représentatives (pour les modéliser, les comparer...).
Afin de garantir un bon traitement et une bonne analyse des données, il faut nettoyer notre dataset. Après avoir visualisé ce dernier, nous avons observé la présence de lignes identiques. Pour garantir la fiabilité de nos analyses, nous avons supprimé ces lignes pour ne pas fausser les résultats.
df = df.drop_duplicates()
df
| time | latitude | longitude | depth | mag | magType | nst | gap | dmin | rms | ... | updated | place | type | horizontalError | depthError | magError | magNst | status | locationSource | magSource | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2023-01-01T00:49:25.294Z | 52.0999 | 178.5218 | 82.770 | 3.10 | ml | 14.0 | 139.0 | 0.8700 | 0.18 | ... | 2023-03-11T22:51:52.040Z | Rat Islands, Aleutian Islands, Alaska | earthquake | 8.46 | 21.213 | 0.097 | 14.0 | reviewed | us | us |
| 1 | 2023-01-01T01:41:43.755Z | 7.1397 | 126.7380 | 79.194 | 4.50 | mb | 32.0 | 104.0 | 1.1520 | 0.47 | ... | 2023-03-11T22:51:45.040Z | 23 km ESE of Manay, Philippines | earthquake | 5.51 | 7.445 | 0.083 | 43.0 | reviewed | us | us |
| 2 | 2023-01-01T03:29:31.070Z | 19.1631 | -66.5251 | 24.000 | 3.93 | md | 23.0 | 246.0 | 0.8479 | 0.22 | ... | 2023-03-11T22:51:29.040Z | Puerto Rico region | earthquake | 0.91 | 15.950 | 0.090 | 16.0 | reviewed | pr | pr |
| 3 | 2023-01-01T04:09:32.814Z | -4.7803 | NaN | 63.787 | 4.30 | mb | 17.0 | 187.0 | 0.4570 | 0.51 | ... | 2023-03-11T22:51:45.040Z | 99 km SSW of Pagar Alam, Indonesia | earthquake | 10.25 | 6.579 | 0.238 | 5.0 | reviewed | us | us |
| 4 | 2023-01-01T04:29:13.793Z | 53.3965 | -166.9417 | 10.000 | 3.00 | ml | 19.0 | 190.0 | 0.4000 | 0.31 | ... | 2023-03-11T22:51:38.040Z | 59 km SSW of Unalaska, Alaska | earthquake | 1.41 | 1.999 | 0.085 | 18.0 | reviewed | us | us |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 26637 | 2023-12-29T03:37:19.334Z | -6.9527 | 154.9829 | 10.000 | 5.20 | mb | 72.0 | 60.0 | 3.9240 | 0.93 | ... | 2023-12-29T04:05:57.040Z | 89 km SW of Panguna, Papua New Guinea | earthquake | 10.07 | 1.765 | 0.048 | 141.0 | reviewed | us | us |
| 26638 | 2023-12-29T04:38:54.109Z | 32.3262 | 141.7386 | 10.000 | 5.10 | mb | 74.0 | 121.0 | 1.8030 | 0.70 | ... | 2023-12-29T10:59:44.533Z | Izu Islands, Japan region | earthquake | 9.17 | 1.870 | 0.042 | 187.0 | reviewed | us | us |
| 26639 | 2023-12-29T08:42:05.747Z | -7.2411 | 68.0663 | 10.000 | 5.10 | mb | 60.0 | 54.0 | 12.7760 | 0.57 | ... | 2023-12-29T08:57:05.040Z | Chagos Archipelago region | earthquake | 8.02 | 1.792 | 0.090 | 40.0 | reviewed | us | us |
| 26640 | 2023-12-29T11:02:48.679Z | -19.1602 | 169.0428 | 153.264 | 4.70 | mb | 40.0 | 61.0 | 3.7460 | 0.82 | ... | 2023-12-29T11:22:46.040Z | 49 km NNW of Isangel, Vanuatu | earthquake | 8.52 | 7.433 | 0.081 | 46.0 | reviewed | us | us |
| 26641 | 2023-12-29T16:31:16.656Z | 25.1050 | 96.5309 | 10.000 | 5.00 | mb | 53.0 | 64.0 | 4.1560 | 0.78 | ... | 2023-12-29T16:45:27.040Z | 92 km WSW of Myitkyina, Myanmar | earthquake | 7.85 | 1.876 | 0.071 | 64.0 | reviewed | us | us |
24682 rows × 22 columns
On remarque que certaines colonnes sont constituées pour certaines de NaN on décide donc de les supprimer. On effectue cela car elles ne nous sont pas utiles dans notre analyse (Ex : Si nous n'avons pas toutes les coordonnées géographiques nous ne pouvons correctement analyser) . Pour cela on execute le code suivant :
df = df.dropna()
df
| time | latitude | longitude | depth | mag | magType | nst | gap | dmin | rms | ... | updated | place | type | horizontalError | depthError | magError | magNst | status | locationSource | magSource | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2023-01-01T00:49:25.294Z | 52.0999 | 178.5218 | 82.770 | 3.10 | ml | 14.0 | 139.0 | 0.8700 | 0.18 | ... | 2023-03-11T22:51:52.040Z | Rat Islands, Aleutian Islands, Alaska | earthquake | 8.46 | 21.213 | 0.097 | 14.0 | reviewed | us | us |
| 1 | 2023-01-01T01:41:43.755Z | 7.1397 | 126.7380 | 79.194 | 4.50 | mb | 32.0 | 104.0 | 1.1520 | 0.47 | ... | 2023-03-11T22:51:45.040Z | 23 km ESE of Manay, Philippines | earthquake | 5.51 | 7.445 | 0.083 | 43.0 | reviewed | us | us |
| 2 | 2023-01-01T03:29:31.070Z | 19.1631 | -66.5251 | 24.000 | 3.93 | md | 23.0 | 246.0 | 0.8479 | 0.22 | ... | 2023-03-11T22:51:29.040Z | Puerto Rico region | earthquake | 0.91 | 15.950 | 0.090 | 16.0 | reviewed | pr | pr |
| 4 | 2023-01-01T04:29:13.793Z | 53.3965 | -166.9417 | 10.000 | 3.00 | ml | 19.0 | 190.0 | 0.4000 | 0.31 | ... | 2023-03-11T22:51:38.040Z | 59 km SSW of Unalaska, Alaska | earthquake | 1.41 | 1.999 | 0.085 | 18.0 | reviewed | us | us |
| 5 | 2023-01-01T04:50:17.639Z | 19.2811 | -155.4282 | 37.751 | 2.80 | ml | 19.0 | 127.0 | 0.0660 | 0.18 | ... | 2023-03-11T22:51:29.040Z | 10 km NNE of P?hala, Hawaii | earthquake | 2.77 | 5.266 | 0.060 | 36.0 | reviewed | us | us |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 26637 | 2023-12-29T03:37:19.334Z | -6.9527 | 154.9829 | 10.000 | 5.20 | mb | 72.0 | 60.0 | 3.9240 | 0.93 | ... | 2023-12-29T04:05:57.040Z | 89 km SW of Panguna, Papua New Guinea | earthquake | 10.07 | 1.765 | 0.048 | 141.0 | reviewed | us | us |
| 26638 | 2023-12-29T04:38:54.109Z | 32.3262 | 141.7386 | 10.000 | 5.10 | mb | 74.0 | 121.0 | 1.8030 | 0.70 | ... | 2023-12-29T10:59:44.533Z | Izu Islands, Japan region | earthquake | 9.17 | 1.870 | 0.042 | 187.0 | reviewed | us | us |
| 26639 | 2023-12-29T08:42:05.747Z | -7.2411 | 68.0663 | 10.000 | 5.10 | mb | 60.0 | 54.0 | 12.7760 | 0.57 | ... | 2023-12-29T08:57:05.040Z | Chagos Archipelago region | earthquake | 8.02 | 1.792 | 0.090 | 40.0 | reviewed | us | us |
| 26640 | 2023-12-29T11:02:48.679Z | -19.1602 | 169.0428 | 153.264 | 4.70 | mb | 40.0 | 61.0 | 3.7460 | 0.82 | ... | 2023-12-29T11:22:46.040Z | 49 km NNW of Isangel, Vanuatu | earthquake | 8.52 | 7.433 | 0.081 | 46.0 | reviewed | us | us |
| 26641 | 2023-12-29T16:31:16.656Z | 25.1050 | 96.5309 | 10.000 | 5.00 | mb | 53.0 | 64.0 | 4.1560 | 0.78 | ... | 2023-12-29T16:45:27.040Z | 92 km WSW of Myitkyina, Myanmar | earthquake | 7.85 | 1.876 | 0.071 | 64.0 | reviewed | us | us |
21080 rows × 22 columns
df.time
0 2023-01-01T00:49:25.294Z
1 2023-01-01T01:41:43.755Z
2 2023-01-01T03:29:31.070Z
4 2023-01-01T04:29:13.793Z
5 2023-01-01T04:50:17.639Z
...
26637 2023-12-29T03:37:19.334Z
26638 2023-12-29T04:38:54.109Z
26639 2023-12-29T08:42:05.747Z
26640 2023-12-29T11:02:48.679Z
26641 2023-12-29T16:31:16.656Z
Name: time, Length: 21080, dtype: object
Dans un contexte de nettoyage et de prétraitement des données, nous avons encodé les variables catégorielles afin qu'elles soient dans un format compréhensible par les algorithmes d'apprentissage automatique.
df.info()
<class 'pandas.core.frame.DataFrame'> Index: 21080 entries, 0 to 26641 Data columns (total 22 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 time 21080 non-null object 1 latitude 21080 non-null float64 2 longitude 21080 non-null float64 3 depth 21080 non-null float64 4 mag 21080 non-null float64 5 magType 21080 non-null object 6 nst 21080 non-null float64 7 gap 21080 non-null float64 8 dmin 21080 non-null float64 9 rms 21080 non-null float64 10 net 21080 non-null object 11 id 21080 non-null object 12 updated 21080 non-null object 13 place 21080 non-null object 14 type 21080 non-null object 15 horizontalError 21080 non-null float64 16 depthError 21080 non-null float64 17 magError 21080 non-null float64 18 magNst 21080 non-null float64 19 status 21080 non-null object 20 locationSource 21080 non-null object 21 magSource 21080 non-null object dtypes: float64(12), object(10) memory usage: 3.7+ MB
Nous normalisons les colonnes time et updated afin qu'elles soient plus lisibles mais également pour que nous puissions encoder les variables catégorielles sans supprimer ces données.
df['time'] = pd.to_datetime(df['time'], format='%Y-%m-%dT%H:%M:%S.%fZ')
df['updated'] = pd.to_datetime(df['updated'], format='%Y-%m-%dT%H:%M:%S.%fZ')
df['time']
df['updated']
C:\Users\Killian\AppData\Local\Temp\ipykernel_20516\1747763810.py:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['time'] = pd.to_datetime(df['time'], format='%Y-%m-%dT%H:%M:%S.%fZ') C:\Users\Killian\AppData\Local\Temp\ipykernel_20516\1747763810.py:3: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['updated'] = pd.to_datetime(df['updated'], format='%Y-%m-%dT%H:%M:%S.%fZ')
0 2023-03-11 22:51:52.040
1 2023-03-11 22:51:45.040
2 2023-03-11 22:51:29.040
4 2023-03-11 22:51:38.040
5 2023-03-11 22:51:29.040
...
26637 2023-12-29 04:05:57.040
26638 2023-12-29 10:59:44.533
26639 2023-12-29 08:57:05.040
26640 2023-12-29 11:22:46.040
26641 2023-12-29 16:45:27.040
Name: updated, Length: 21080, dtype: datetime64[ns]
from sklearn.preprocessing import LabelEncoder
label_encoder = LabelEncoder()
colonnes_a_exclure = ['place', 'id', 'type']
for colonne in df.columns:
if colonne not in colonnes_a_exclure and df[colonne].dtypes == 'object':
df[colonne] = label_encoder.fit_transform(df[colonne])
print(df[colonne])
df.info()
0 3
1 0
2 2
4 3
5 3
..
26637 0
26638 0
26639 0
26640 0
26641 0
Name: magType, Length: 21080, dtype: int32
0 7
1 7
2 4
4 7
5 7
..
26637 7
26638 7
26639 7
26640 7
26641 7
Name: net, Length: 21080, dtype: int32
0 1
1 1
2 1
4 1
5 1
..
26637 1
26638 1
26639 1
26640 1
26641 1
Name: status, Length: 21080, dtype: int32
0 7
1 7
2 4
4 7
5 7
..
26637 7
26638 7
26639 7
26640 7
26641 7
Name: locationSource, Length: 21080, dtype: int32
0 7
1 7
2 4
4 7
5 7
..
26637 7
26638 7
26639 7
26640 7
26641 7
Name: magSource, Length: 21080, dtype: int32
<class 'pandas.core.frame.DataFrame'>
Index: 21080 entries, 0 to 26641
Data columns (total 22 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 time 21080 non-null datetime64[ns]
1 latitude 21080 non-null float64
2 longitude 21080 non-null float64
3 depth 21080 non-null float64
4 mag 21080 non-null float64
5 magType 21080 non-null int32
6 nst 21080 non-null float64
7 gap 21080 non-null float64
8 dmin 21080 non-null float64
9 rms 21080 non-null float64
10 net 21080 non-null int32
11 id 21080 non-null object
12 updated 21080 non-null datetime64[ns]
13 place 21080 non-null object
14 type 21080 non-null object
15 horizontalError 21080 non-null float64
16 depthError 21080 non-null float64
17 magError 21080 non-null float64
18 magNst 21080 non-null float64
19 status 21080 non-null int32
20 locationSource 21080 non-null int32
21 magSource 21080 non-null int32
dtypes: datetime64[ns](2), float64(12), int32(5), object(3)
memory usage: 3.3+ MB
C:\Users\Killian\AppData\Local\Temp\ipykernel_20516\3547750565.py:9: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df[colonne] = label_encoder.fit_transform(df[colonne]) C:\Users\Killian\AppData\Local\Temp\ipykernel_20516\3547750565.py:9: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df[colonne] = label_encoder.fit_transform(df[colonne]) C:\Users\Killian\AppData\Local\Temp\ipykernel_20516\3547750565.py:9: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df[colonne] = label_encoder.fit_transform(df[colonne]) C:\Users\Killian\AppData\Local\Temp\ipykernel_20516\3547750565.py:9: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df[colonne] = label_encoder.fit_transform(df[colonne]) C:\Users\Killian\AppData\Local\Temp\ipykernel_20516\3547750565.py:9: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df[colonne] = label_encoder.fit_transform(df[colonne])
Nous avons encodé les variables catégorielles afin qu'elles soient dans un format compréhensible par les algorithmes d'apprentissage automatique
df.info()
<class 'pandas.core.frame.DataFrame'> Index: 21080 entries, 0 to 26641 Data columns (total 22 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 time 21080 non-null datetime64[ns] 1 latitude 21080 non-null float64 2 longitude 21080 non-null float64 3 depth 21080 non-null float64 4 mag 21080 non-null float64 5 magType 21080 non-null int32 6 nst 21080 non-null float64 7 gap 21080 non-null float64 8 dmin 21080 non-null float64 9 rms 21080 non-null float64 10 net 21080 non-null int32 11 id 21080 non-null object 12 updated 21080 non-null datetime64[ns] 13 place 21080 non-null object 14 type 21080 non-null object 15 horizontalError 21080 non-null float64 16 depthError 21080 non-null float64 17 magError 21080 non-null float64 18 magNst 21080 non-null float64 19 status 21080 non-null int32 20 locationSource 21080 non-null int32 21 magSource 21080 non-null int32 dtypes: datetime64[ns](2), float64(12), int32(5), object(3) memory usage: 3.3+ MB
Pour effectuez une analyse descriptive des données, nous allons commencer par résumé les variables numériques
print(df.describe())
time latitude longitude \
count 21080 21080.000000 21080.000000
mean 2023-06-28 14:41:49.917795840 15.680956 -3.106846
min 2023-01-01 00:49:25.294000 -65.849700 -179.998700
25% 2023-03-25 19:21:46.375500032 -6.513600 -118.385000
50% 2023-06-25 20:33:20.763500032 18.227500 -26.733400
75% 2023-10-01 13:39:05.907749888 38.858675 127.268800
max 2023-12-29 23:17:18.800000 86.593900 179.999400
std NaN 29.314531 128.808562
depth mag magType nst gap \
count 21080.000000 21080.000000 21080.000000 21080.000000 21080.000000
mean 68.321158 4.048470 1.605408 42.528795 127.081074
min -3.370000 2.600000 0.000000 3.000000 8.000000
25% 10.000000 3.370000 0.000000 18.000000 73.000000
50% 21.532000 4.300000 0.000000 29.000000 113.000000
75% 66.333250 4.500000 3.000000 52.000000 172.000000
max 681.238000 7.800000 11.000000 423.000000 350.000000
std 118.155052 0.786942 2.833168 38.923838 69.076922
dmin rms net \
count 21080.000000 21080.000000 21080.000000
mean 2.551639 0.578899 6.551044
min 0.000000 0.010000 0.000000
25% 0.576975 0.400000 7.000000
50% 1.491000 0.580000 7.000000
75% 3.074000 0.750000 7.000000
max 50.820000 1.880000 9.000000
std 3.805738 0.255945 1.297837
updated horizontalError depthError \
count 21080 21080.000000 21080.000000
mean 2023-08-24 08:20:55.669221120 6.963787 4.800911
min 2023-01-01 11:14:15.230000 0.000000 0.100000
25% 2023-05-26 21:54:07.790000128 4.100000 1.878000
50% 2023-08-26 20:54:24.040000 6.980000 2.693000
75% 2023-11-28 18:44:39.960250112 9.620000 6.955250
max 2023-12-30 00:23:54.040000 99.000000 47.878000
std NaN 4.037148 4.577801
magError magNst status locationSource magSource
count 21080.000000 21080.000000 21080.000000 21080.000000 21080.000000
mean 0.118441 33.598482 0.999573 6.551044 6.551044
min 0.000000 0.000000 0.000000 0.000000 0.000000
25% 0.078000 10.000000 1.000000 7.000000 7.000000
50% 0.108000 18.000000 1.000000 7.000000 7.000000
75% 0.148000 36.000000 1.000000 7.000000 7.000000
max 0.770000 884.000000 1.000000 9.000000 9.000000
std 0.058194 49.353409 0.020659 1.297837 1.297837
Nous remarquons qu'il y a quelques valeurs aberrantes comme par exemple l'écart entre la valeur moyenne et la valeur max de la colonne magNst.
Nous pouvons aussi obtenir la fréquence des différentes catégories
print(df.magNst.value_counts())
magNst
10.0 1124
12.0 1012
8.0 989
14.0 933
6.0 862
...
273.0 1
457.0 1
500.0 1
257.0 1
404.0 1
Name: count, Length: 379, dtype: int64
D'autre part, nous pouvons obtenir la matrice de corrélation entre les variables numériques pour corréler les valeurs.
colonne_num = df.select_dtypes(include='number')
correlation_matrix = colonne_num.corr()
print(correlation_matrix)
latitude longitude depth mag magType nst \
latitude 1.000000 -0.180172 -0.279452 -0.534165 0.174312 -0.002172
longitude -0.180172 1.000000 -0.054961 0.491289 -0.164641 0.151647
depth -0.279452 -0.054961 1.000000 0.143370 -0.135157 0.064436
mag -0.534165 0.491289 0.143370 1.000000 0.009480 0.528265
magType 0.174312 -0.164641 -0.135157 0.009480 1.000000 0.405277
nst -0.002172 0.151647 0.064436 0.528265 0.405277 1.000000
gap 0.311072 -0.299297 -0.179294 -0.540287 -0.036322 -0.476688
dmin -0.355968 0.186362 0.041044 0.354928 -0.108273 0.068382
rms -0.219160 0.213494 0.097704 0.494904 -0.077533 0.183966
net -0.126499 0.233183 0.136797 0.413283 -0.090965 0.090476
horizontalError -0.411654 0.283793 0.415469 0.470323 -0.254747 0.022009
depthError -0.034863 -0.034154 0.326831 -0.036556 -0.101855 -0.142591
magError -0.156546 0.014150 -0.036732 -0.133314 -0.277945 -0.430332
magNst 0.027111 0.043381 0.099790 0.247017 -0.090177 0.499504
status -0.014022 0.018107 0.011054 0.032293 -0.009363 0.008422
locationSource -0.126499 0.233183 0.136797 0.413283 -0.090965 0.090476
magSource -0.126499 0.233183 0.136797 0.413283 -0.090965 0.090476
gap dmin rms net horizontalError \
latitude 0.311072 -0.355968 -0.219160 -0.126499 -0.411654
longitude -0.299297 0.186362 0.213494 0.233183 0.283793
depth -0.179294 0.041044 0.097704 0.136797 0.415469
mag -0.540287 0.354928 0.494904 0.413283 0.470323
magType -0.036322 -0.108273 -0.077533 -0.090965 -0.254747
nst -0.476688 0.068382 0.183966 0.090476 0.022009
gap 1.000000 -0.168113 -0.262887 -0.172500 -0.130615
dmin -0.168113 1.000000 0.145757 0.202912 0.432698
rms -0.262887 0.145757 1.000000 0.486624 0.334725
net -0.172500 0.202912 0.486624 1.000000 0.480372
horizontalError -0.130615 0.432698 0.334725 0.480372 1.000000
depthError 0.239580 -0.080188 0.017430 0.000588 0.227445
magError 0.069712 -0.010270 -0.058038 -0.075433 0.044140
magNst -0.296739 0.041580 0.099376 -0.015280 0.016140
status 0.000955 0.013104 0.031942 0.054780 0.029911
locationSource -0.172500 0.202912 0.486624 1.000000 0.480372
magSource -0.172500 0.202912 0.486624 1.000000 0.480372
depthError magError magNst status locationSource \
latitude -0.034863 -0.156546 0.027111 -0.014022 -0.126499
longitude -0.034154 0.014150 0.043381 0.018107 0.233183
depth 0.326831 -0.036732 0.099790 0.011054 0.136797
mag -0.036556 -0.133314 0.247017 0.032293 0.413283
magType -0.101855 -0.277945 -0.090177 -0.009363 -0.090965
nst -0.142591 -0.430332 0.499504 0.008422 0.090476
gap 0.239580 0.069712 -0.296739 0.000955 -0.172500
dmin -0.080188 -0.010270 0.041580 0.013104 0.202912
rms 0.017430 -0.058038 0.099376 0.031942 0.486624
net 0.000588 -0.075433 -0.015280 0.054780 1.000000
horizontalError 0.227445 0.044140 0.016140 0.029911 0.480372
depthError 1.000000 0.013334 -0.075370 -0.009574 0.000588
magError 0.013334 1.000000 -0.427177 -0.020402 -0.075433
magNst -0.075370 -0.427177 1.000000 0.002391 -0.015280
status -0.009574 -0.020402 0.002391 1.000000 0.054780
locationSource 0.000588 -0.075433 -0.015280 0.054780 1.000000
magSource 0.000588 -0.075433 -0.015280 0.054780 1.000000
magSource
latitude -0.126499
longitude 0.233183
depth 0.136797
mag 0.413283
magType -0.090965
nst 0.090476
gap -0.172500
dmin 0.202912
rms 0.486624
net 1.000000
horizontalError 0.480372
depthError 0.000588
magError -0.075433
magNst -0.015280
status 0.054780
locationSource 1.000000
magSource 1.000000
Une matrice de corrélation nous indique plusieurs choses. Les valeurs vont de -1 à 1 :
1 indique une corrélation positive parfaite. -1 indique une corrélation négative parfaite. 0 indique aucune corrélation.
Par exemple :
Erreur horizontale dans la détermination de l'emplacement (horizontalError) vs. Profondeur (depth) : Il y a une corrélation positive moyenne (0,42), montrant qu'à mesure que la profondeur du séisme augmente, l'erreur horizontale dans la détermination de l'emplacement a aussi tendance à augmenter.
Enfin, nous pouvons obtenir des statistiques temporelles pour mieux situer nos données dans le temps
time_stat = df['time'].describe()
print(time_stat)
update_stat = df['updated'].describe()
print(update_stat)
count 21080 mean 2023-06-28 14:41:49.917795840 min 2023-01-01 00:49:25.294000 25% 2023-03-25 19:21:46.375500032 50% 2023-06-25 20:33:20.763500032 75% 2023-10-01 13:39:05.907749888 max 2023-12-29 23:17:18.800000 Name: time, dtype: object count 21080 mean 2023-08-24 08:20:55.669221120 min 2023-01-01 11:14:15.230000 25% 2023-05-26 21:54:07.790000128 50% 2023-08-26 20:54:24.040000 75% 2023-11-28 18:44:39.960250112 max 2023-12-30 00:23:54.040000 Name: updated, dtype: object
Suite à ces analyses, nous allons tracer un boxplot pour visualiser avec précisions ces valeurs aberrantes.
Cette étape nous servira dans notre choix de modèle de machine learning.
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(12, 6))
sns.boxplot(data=df)
plt.xticks(rotation=45)
plt.show()
Cette visualisation nous permet de nous rendre compte des écarts possibles entre les valeurs moyennes/minimums/maximum. De plus nous voyons que plus les boxs sont étirées plus il y a de valeurs abérrantes. (Nous confirmons bien que magNstet depthcontiennt des valeurs abérrantes)
On peut aussi analyser les types de catastrophes sysmiques afin de mieux comprendre le jeu de données et rendre nos analyses plus pertinentes.
import plotly.express as px
earthquake_type = df['type'].value_counts()
fig = px.bar(y = earthquake_type.values, x = earthquake_type.index, color = earthquake_type.index, text = earthquake_type.values)
fig.show()
Nous voyons qu'il y a une grande majorité d'earthquake dans notre dataframe. Nous allons donc choisir ce type pour notre algorithme
Afin de mieux comprendre les données, on a choisi de mettre sous forme de nuage de points la magnitude en fonction de la date du séisme.
plt.figure(figsize=(10, 6))
sns.scatterplot(x='time', y='mag', data=df, s=50)
plt.xlabel('date')
plt.ylabel('magnitude')
plt.show()
On peut voir que des séismes de forte magnitude (>6.5) ont lieux régulièrements dans l'année, cependant on note une tendance plus élevée en début d'année 2023. D'autre part, on voit que la plupart des séismes ont une magnitude moyenne (entre 4 & 5)
On va s'intéresser au tremblement de terre de magnitude supérieur à 5 afin de voir les zones à haut risque de tremblement dévastateur.
import folium
carte = folium.Map(location=[43.327408, -1.032999], zoom_start = 2)
for ind, i in df.iterrows():
if i['type'] == 'earthquake' and i['mag'] > 5:
carte.add_child(folium.RegularPolygonMarker(location = [i['latitude'], i['longitude']], popup = i['place'], fill_color = 'red', radius = 10))
carte
On remarque que l'océan Pacifique est l'endroit où les tremblements de terre ont tendance à être plus forts que la moyenne (magnitude > 5)
Au vue des explorations effectuées, nous voulons prédire le nombre de séismes avec une magnitude supérieure à 5.
Nous avons vu en cours plusieurs algorithmes de machine learning. Nous allons évaluer ces algorithmes pour choisir celui qui correspond le mieux à notre besoin.
On cherche à expliquer les variations d’une variable dépendante Y (variable réponse) avec celles d’une ou plusieurs variables indépendantes (variables explicatives). Pour cela on modélise une relation linéaire. Pour la régression linéaire simple une seule variable indépendante est utilisée pour prédire une variable dépendante.
C'est un peu près la même chose que la la régression linéaire simple mais cette fois plusieurs variables indépendantes sont utilisées pour prédire une variable dépendante.
Ce dernier n'est pas applicable pour notre prédiction étant donné que l'on utilise une seule variable indépendante.
C’est un modèle d'apprentissage supervisé qui utilise des données étiquetées pour faire des prédictions. Il utilise l'estimation du maximum de vraisemblance (MLE) qui détermine les paramètres (moyenne et variance) permettant de maximiser la probabilité de produire le résultat souhaité.
Le principe de l'algorithme K-means est de s'entrainer sur un jeu de données sans réponses préexistante, il tire des conclusions sur des données non étiquetées. On peut l'utiliser dans des cas comme la reconnaissance vocale, le classement des données ou même la compression d'images , etc ..
Cependant cet algorithme n'est pas applicable dans notre cas. En effet ce dernier vise à séparer nos données en clusters et ne sert donc pas pour notre prédiction.
Les K-plus proches voisins (KNN) représentent une catégorie d'algorithmes d'apprentissage supervisé exploités à des fins de régression et de classification, leur utilisation principale se concentre sur des problèmes de classification.
L'algorithme d'analyse hiérarchique ascendante (HCA) organise les données de manière hiérarchique en fusionnant itérativement les clusters les plus similaires, offrant ainsi une visualisation structurelle via un dendrogramme et permettant une analyse approfondie de la similarité entre les observations.
L'algorithme n'est pas applicable à notre cas. En effet ce dernier n'est pas orienté pour de la prédiction mais plus pour de la classification hiérarchique de données.
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score, confusion_matrix, mean_squared_error, classification_report, precision_score, f1_score, recall_score
Création des données d'entrainement :
X = df[['latitude', 'longitude', 'mag']]
y = (df['mag'] > 5).astype(int)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.7, random_state = 42)
On normalise nos données :
scaler = MinMaxScaler()
X_train_norm = scaler.fit_transform(X_train)
X_test_norm = scaler.transform(X_test)
On les encode :
label_encoder = LabelEncoder()
y = label_encoder.fit_transform(y)
On met en place la Régression linéaire pour l'évaluer :
regression_lineaire = LinearRegression()
regression_lineaire.fit(X_train_norm, y_train)
y_pred_lineaire = regression_lineaire.predict(X_test_norm)
On met en place la Régression logistique pour l'évaluer :
regression_logistique = LogisticRegression()
regression_logistique.fit(X_train_norm, y_train)
y_pred_logistique = regression_logistique.predict(X_test_norm)
On met en place KNN pour l'évaluer :
knn_model = KNeighborsClassifier(n_neighbors=3)
knn_model.fit(X_train_norm, y_train)
y_pred_knn = knn_model.predict(X_test_norm)
precision_logistique = accuracy_score(y_test, y_pred_logistique)
precision_knn = accuracy_score(y_test, y_pred_knn)
print(f'Erreur quadratique (Régression Linéaire) : {mean_squared_error(y_test, y_pred_lineaire)}\n')
print(f'Précision (Régression Logistique) : {precision_logistique * 100}')
print(f'Erreur quadratique (Régression Logistique) : {mean_squared_error(y_test, y_pred_logistique)}\n')
print(f'Précision (KNN) : {precision_knn * 100}')
print(f'Erreur quadratique (KNN) : {mean_squared_error(y_test, y_pred_knn)}')
Erreur quadratique (Régression Linéaire) : 0.043035068198020276 Précision (Régression Logistique) : 96.76063973976687 Erreur quadratique (Régression Logistique) : 0.032393602602331255 Précision (KNN) : 99.39007861209 Erreur quadratique (KNN) : 0.006099213879100027
confusion_mat_reg_logistique = confusion_matrix(y_test, y_pred_logistique)
sns.heatmap(confusion_mat_reg_logistique, annot = True, fmt = 'd', cmap = 'Blues', xticklabels = ['Magnitude inférieure à 5', 'Magnitude supérieure à 5'], yticklabels = ['Magnitude inférieure à 5', 'Magnitude supérieure à 5'])
plt.title('Matrice de confusion Régression Logistique')
plt.xlabel('Prédictions')
plt.ylabel('Vraies valeurs')
plt.show()
confusion_mat_knn = confusion_matrix(y_test, y_pred_knn)
sns.heatmap(confusion_mat_knn, annot = True, fmt = 'd', cmap = 'Blues', xticklabels = ['Magnitude inférieure à 5', 'Magnitude supérieure à 5'], yticklabels = ['Magnitude inférieure à 5', 'Magnitude supérieure à 5'])
plt.title('Matrice de confusion KNN')
plt.xlabel('Prédictions')
plt.ylabel('Vraies valeurs')
plt.show()
Nous remarquons alors que l'algorithme KNN nous permet d'avoir plus de prédiction sur la caractéristique ciblée.
Compte tenu de notre but : prédir le nombre de tremblement de terre de magnitude supérieur à 5 nous avons choisi l'algorithme : KNN. En effet, cet algorithme est plus précit pour notre problème de prédiction.
On peut par exemple utiliser la latitude, la longitude, et d'autres caractéristiques comme variables explicatives pour prédire si un tremblement de terre de haute intensité se produira.
On vérifie que notre dataframe ne contient pas de valeurs null
df.isnull().sum()
time 0 latitude 0 longitude 0 depth 0 mag 0 magType 0 nst 0 gap 0 dmin 0 rms 0 net 0 id 0 updated 0 place 0 type 0 horizontalError 0 depthError 0 magError 0 magNst 0 status 0 locationSource 0 magSource 0 dtype: int64
On veut alors prédire le nombre de tremblements de terre avec une magnitude supérieure à 5 :
On créer alors nos ensembles de données d'entraînement et de test :
X = df[['latitude', 'longitude', 'mag']]
y = (df['mag'] > 5).astype(int)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.7, random_state = 42)
On réalise une mise à l'échelle
scaler = MinMaxScaler()
X_train_norm = scaler.fit_transform(X_train)
X_test_norm = scaler.transform(X_test)
On procède à l'encodage de nos données : (0 si la magnitude est inférieure à 5 sinon 1)
label_encoder = LabelEncoder()
y = label_encoder.fit_transform(y)
print(y)
[0 0 0 ... 1 0 0]
On applique notre algorithme KNN, pour entrainer le modèle :
knn_model = KNeighborsClassifier(n_neighbors=3)
knn_model.fit(X_train_norm, y_train)
y_pred_knn = knn_model.predict(X_test_norm)
On prédit alors nos résultats en faisant intervenir une matrice de confusion pour vérifier les prédictions.
confusion_mat_knn = confusion_matrix(y_test, y_pred_knn)
sns.heatmap(confusion_mat_knn, annot = True, fmt = 'd', cmap = 'Blues', xticklabels = ['Magnitude inférieure à 5', 'Magnitude supérieure à 5'], yticklabels = ['Magnitude inférieure à 5', 'Magnitude supérieure à 5'])
plt.title('Matrice de confusion KNN')
plt.xlabel('Prédictions')
plt.ylabel('Vraies valeurs')
plt.show()
On voit qu'on arrive à prédire 817 séismes avec une magnitude supérieure à 5
Comme très peu de tremblements de terre ont une magnitude supérieure à 5, on arrive avec précision (≃ 100%) à prédire le nombre de tremblements de terre de ce type dans le futur.
On va maintenant l'entrainer pour avoir des prédictions plus juste :
Pour ce faire on utilise l'outil GridSearchCV :
from sklearn.model_selection import GridSearchCV
param_grid = {'n_neighbors': [3, 5, 7, 9]}
grid_search = GridSearchCV(knn_model, param_grid, scoring='accuracy')
grid_search.fit(X_train_norm, y_train)
meilleurs_parametres = grid_search.best_params_
print(f'Meilleurs hyperparamètres : {meilleurs_parametres}')
meilleur_algo = grid_search.best_estimator_
y_pred_knn2 = meilleur_algo.predict(X_test_norm)
precision_knn2 = accuracy_score(y_test, y_pred_knn2)
print(f'Précision : {precision_knn2 * 100} %')
Meilleurs hyperparamètres : {'n_neighbors': 3}
Précision : 99.39007861209 %
On voit que nos prévisions sont les plus précises avec un paramétrage à k = 3
Afin d'évaluer notre modèle, on utilise une métrique se nommant RMSE (Root Mean Square Error).
mse = mean_squared_error(y_test, y_pred_knn)
print(f'Mean Squared Error: {mse}')
Mean Squared Error: 0.006099213879100027
On voit que comme notre erreur quadratique est proche de 0 nos prédictions sont précises.
On peut de plus utiliser les métriques RECALL/F1-SCORE/ Précision pour mieux évaluer notre modèle :
print(classification_report(y_test,y_pred_knn))
precision recall f1-score support
0 0.99 1.00 1.00 13855
1 0.99 0.91 0.95 901
accuracy 0.99 14756
macro avg 0.99 0.95 0.97 14756
weighted avg 0.99 0.99 0.99 14756
Toutes ces valeurs étant basses, nous indiquent une bonne fiabilité de notre algorithme dans nos prédictions.
faux_positif = confusion_mat_knn[0, 1] / (confusion_mat_knn[0, 1] +
confusion_mat_knn[1, 1])
print('Taux de Faux Positifs:', faux_positif * 100)
Taux de Faux Positifs: 0.7290400972053462
De plus, nous voyons que nous avons un très faible taux de faux positif. Ce qui appui d'autant plus la fiabilité de notre algorithme.
Dans l'algorithme KNN, on peut optimiser plusieurs paramètres : nombre de voisins, la distance utilisée, etc.
C'est ce que nous cherchons à faire dans cette partie :
param_grid = {'n_neighbors': [3, 5, 7, 9], 'metric': ['euclidean', 'manhattan', 'minkowski', 'cosinus']}
grid_search = GridSearchCV(knn_model, param_grid, scoring='accuracy')
grid_search.fit(X_train_norm, y_train)
Parametres_opti = grid_search.best_params_
print(f'Meilleurs hyperparamètres : {Parametres_opti}')
meilleur_algo = grid_search.best_estimator_
y_pred_knn3 = meilleur_algo.predict(X_test_norm)
precision_knn3 = accuracy_score(y_test, y_pred_knn3)
print(f'Précision (KNN avec meilleurs paramètres) : {precision_knn3 * 100}')
D:\anaconda3\Lib\site-packages\sklearn\model_selection\_validation.py:378: FitFailedWarning:
20 fits failed out of a total of 80.
The score on these train-test partitions for these parameters will be set to nan.
If these failures are not expected, you can try to debug them by setting error_score='raise'.
Below are more details about the failures:
--------------------------------------------------------------------------------
20 fits failed with the following error:
Traceback (most recent call last):
File "D:\anaconda3\Lib\site-packages\sklearn\model_selection\_validation.py", line 686, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "D:\anaconda3\Lib\site-packages\sklearn\neighbors\_classification.py", line 207, in fit
return self._fit(X, y)
^^^^^^^^^^^^^^^
File "D:\anaconda3\Lib\site-packages\sklearn\neighbors\_base.py", line 446, in _fit
self._check_algorithm_metric()
File "D:\anaconda3\Lib\site-packages\sklearn\neighbors\_base.py", line 381, in _check_algorithm_metric
raise ValueError(
ValueError: Metric 'cosinus' not valid. Use sorted(sklearn.neighbors.VALID_METRICS['brute']) to get valid options. Metric can also be a callable function.
D:\anaconda3\Lib\site-packages\sklearn\model_selection\_search.py:953: UserWarning:
One or more of the test scores are non-finite: [0.99399072 0.99351616 0.99161868 0.99082804 0.99399072 0.99351629
0.99177703 0.9900379 0.99399072 0.99351616 0.99161868 0.99082804
nan nan nan nan]
Meilleurs hyperparamètres : {'metric': 'euclidean', 'n_neighbors': 3}
Précision (KNN avec meilleurs paramètres) : 99.39007861209
if faux_positif > 0.01:
print('L\'intégrité de vos données se dégrade, veuillez réctifier votre modèle ')
else:
print(f'Votre modèle propose des données cohérentes, le taux de faux positif est de {faux_positif * 100} %')
Votre modèle propose des données cohérentes, le taux de faux positif est de 0.7290400972053462 %
Nos données provenant du dataset earthquake_2023, nous pourrons alimenter notre algorithme de prédiction avec de futurs données (Ex : Tremblements de terre 2024)